package report

import (
	"context"
	"errors"
	nodev1 "node-operator/api/v1"
	"time"

	logr "github.com/sirupsen/logrus"

	corev1 "k8s.io/api/core/v1"
	clicorev1 "k8s.io/client-go/kubernetes/typed/core/v1"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	metricsapi "k8s.io/metrics/pkg/apis/metrics"
)

var (
	DeletedNodes          []nodev1.Node
	DeletedNodeReportChan chan *nodev1.Node
	UpdateNodeReportChan  chan *nodev1.Node
)

func init() {
	DeletedNodeReportChan = make(chan *nodev1.Node)
	UpdateNodeReportChan = make(chan *nodev1.Node)
}

type Reporter interface {
	Start(ctx context.Context)
	updateNodeMetrics(ctx context.Context)
}

func calculateNodeMetrics(nodeClient clicorev1.CoreV1Interface, nodeMetrics *metricsapi.NodeMetricsList) (*nodev1.NodeList, error) {
	if len(nodeMetrics.Items) == 0 {
		return nil, errors.New("Metrics not available yet")
	}

	//准备usage, allocatable
	nodeList, err := nodeClient.Nodes().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, err
	}
	capacity := make(map[string]corev1.ResourceList)
	for _, n := range nodeList.Items {
		capacity[n.Name] = n.Status.Capacity
	}

	usage := make(map[string]corev1.ResourceList)
	for _, n := range nodeMetrics.Items {
		usage[n.Name] = n.Usage
	}

	//计算metrics
	nodeResults := nodev1.NodeList{}
	for _, node := range nodeList.Items {
		var cpuCores float64
		var cpuPercent float64
		var memoryBytes float64
		var memoryPercent float64

		nodeName := node.Name
		//从api-server得到的node可能多于从metrics-server得到的node
		quantity, found := usage[nodeName]
		if !found {
			logr.Warnf("Node %s not found in metrics list\n", nodeName)
			continue
		} else {
			capacity := capacity[nodeName]
			cpuFraction := float64(quantity.Cpu().MilliValue()) / float64(capacity.Cpu().MilliValue())
			memoryFraction := float64(quantity.Memory().MilliValue()) / float64(capacity.Memory().MilliValue())

			cpuCores = float64(quantity.Cpu().MilliValue()) / 1000.0
			cpuPercent = cpuFraction
			memoryBytes = float64(quantity.Memory().MilliValue() / 1000.0)
			memoryPercent = memoryFraction
		}

		nodeResult := nodev1.Node{
			Name:  nodeName,
			IP:    node.Status.Addresses[0].Address,
			InK8s: "True",
			Status: nodev1.NodeStatus{
				Ready:              string(node.Status.Conditions[len(node.Status.Conditions)-1].Status),
				NetworkUnavailable: string(node.Status.Conditions[0].Status),
				MemoryPressure:     string(node.Status.Conditions[1].Status),
				DiskPressure:       string(node.Status.Conditions[2].Status),
				PIDPressure:        string(node.Status.Conditions[3].Status),
				CPU: nodev1.CPUStatus{
					Cores:   cpuCores,
					Percent: cpuPercent,
				},
				Memory: nodev1.MemoryStatus{
					Bytes:   memoryBytes,
					Percent: memoryPercent,
				},
				Time: time.Now().UnixNano() / 1e6,
			},
		}
		logr.Debugf("%+v", nodeResult)
		nodeResults.Nodes = append(nodeResults.Nodes, nodeResult)
	}

	return &nodeResults, nil
}
